package yiran.stock;

import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import yiran.stock.manager.StockCacheManager;
import yiran.stock.manager.StockDataFetcher;
import yiran.stock.manager.StockPriceUpdateEvent;
import yiran.stock.output.Logger;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class StockManager {
    public static final int MAX_RETRIES = 3;
    public static final long API_CACHE_TIME = 60000;
    public static final long REQUEST_INTERVAL = 1000;

    private final JavaPlugin plugin;
    private BukkitTask stockUpdateTask;
    private ApiProvider currentApiProvider;
    private final StockDataFetcher dataFetcher;
    private final StockCacheManager cacheManager;
    private final Map<String, Integer> failureCounts = new ConcurrentHashMap<>();

    public enum ApiProvider {
        QQ("QQ财经", "https://qt.gtimg.cn/q=");

        final String name;
        public final String baseUrl;

        ApiProvider(String name, String baseUrl) {
            this.name = name;
            this.baseUrl = baseUrl;
        }
    }

    public StockManager(JavaPlugin plugin) {
        this.plugin = plugin;
        this.cacheManager = new StockCacheManager();
        this.dataFetcher = new StockDataFetcher(this);
    }

    public void initialize() {
        currentApiProvider = ApiProvider.QQ;
        Logger.info("使用股票数据源: " + currentApiProvider.name);

        for (String symbol : plugin.getConfig().getStringList("stocks")) {
            String lowerSymbol = symbol.toLowerCase();
            cacheManager.cacheStockPrice(lowerSymbol, 0.0);
            cacheManager.cachePreviousPrice(lowerSymbol, 0.0);
        }
    }

    public void start() {
        int updateInterval = plugin.getConfig().getInt("update-interval", 120);
        stockUpdateTask = plugin.getServer().getScheduler().runTaskTimerAsynchronously(
                plugin, this::updateAllStockPrices, 0L, updateInterval * 20L
        );
        Logger.info("A股市场模拟系统已启动");
    }

    public boolean loadStockIfNeeded(String symbol) {
        String lowerSymbol = symbol.toLowerCase();

        if (failureCounts.getOrDefault(lowerSymbol, 0) >= 3) {
            return false;
        }

        if (cacheManager.isStockLoaded(lowerSymbol)) {
            return true;
        }

        try {
            String name = getStockNameFromAPI(lowerSymbol);
            double price = getRealStockPrice(lowerSymbol);

            cacheManager.cacheStockName(lowerSymbol, name);
            cacheManager.cacheStockPrice(lowerSymbol, price);
            cacheManager.cachePreviousPrice(lowerSymbol, price);
            cacheManager.markStockLoaded(lowerSymbol);

            List<String> stocks = plugin.getConfig().getStringList("stocks");
            if (!stocks.contains(lowerSymbol)) {
                stocks.add(lowerSymbol);
                plugin.getConfig().set("stocks", stocks);
                plugin.saveConfig();
            }

            return true;
        } catch (Exception e) {
            int failures = failureCounts.getOrDefault(lowerSymbol, 0) + 1;
            failureCounts.put(lowerSymbol, failures);

            if (failures >= 3) {
                removeFailedStock(lowerSymbol);
            }

            return false;
        }
    }

    private String getStockNameFromAPI(String symbol) throws IOException {
        if (cacheManager.isCacheValid(symbol, API_CACHE_TIME)) {
            String name = cacheManager.getStockName(symbol);
            if (name != null && !name.trim().isEmpty() &&
                    !name.equalsIgnoreCase(symbol) &&
                    !name.contains("未知股票") &&
                    !name.contains("加载失败")) {
                return name;
            }
        }

        String response = dataFetcher.fetchApiData(symbol);
        String[] data = dataFetcher.parseApiResponse(response);

        if (data == null || data.length < 2) {
            throw new IOException("API返回无效数据: " + response);
        }

        String name = getString(symbol, data);

        cacheManager.cacheStockName(symbol, name);
        cacheManager.updateLastApiCall(symbol);
        return name;
    }

    private String getString(String symbol, String[] data) {
        String name = data[1];

        // 多层级名称验证
        if (name == null) {
            name = "未知股票";
        } else if (name.trim().isEmpty()) {
            name = "未命名股票";
        } else if (name.equals(symbol)) {
            name = "未知股票(" + symbol + ")";
        } else if (name.matches("^[0-9]+$")) {
            name = "代码股票(" + symbol + ")";
        } else if (name.contains("?")) {
            name = name.replace("?", " ").trim();
        } else if (name.length() > 20) {
            name = name.substring(0, 17) + "...";
        }
        return name;
    }

    private double getRealStockPrice(String symbol) throws IOException {
        if (cacheManager.isCacheValid(symbol, API_CACHE_TIME)) {
            Double cachedPrice = cacheManager.getCachedPrice(symbol);
            if (cachedPrice == null) {
                Logger.warn("缓存有效但价格为空，重新请求API: " + symbol);
            } else {
                return cachedPrice;
            }
        }

        try {
            String response = dataFetcher.fetchApiData(symbol);
            String[] data = dataFetcher.parseApiResponse(response);
            double price = getPrice(data);

            cacheManager.cacheStockPrice(symbol, price);
            return price;
        } catch (Exception e) {
            Logger.error("获取股票价格失败: " + symbol + " - " + e.getMessage());

            cacheManager.cacheStockPrice(symbol, 0.01);
            throw new IOException("API请求失败: " + e.getMessage());
        } finally {
            cacheManager.updateLastApiCall(symbol);
        }
    }

    private double getPrice(String[] data) throws IOException {
        double price;

        if (Objects.requireNonNull(currentApiProvider) == ApiProvider.QQ) {
            if (data.length <= 3) {
                throw new IOException("无效的API响应格式: 数据字段不足(" + data.length + ")");
            }

            if (data[3] == null || data[3].trim().isEmpty()) {
                throw new IOException("价格字段为空");
            }

            try {
                price = Double.parseDouble(data[3]);
            } catch (NumberFormatException e) {
                throw new IOException("无效的价格格式: " + data[3]);
            }
        } else {
            throw new IOException("不支持的API提供商: " + currentApiProvider);
        }
        return price;
    }

    public void stop() {
        if (stockUpdateTask != null) {
            stockUpdateTask.cancel();
            stockUpdateTask = null;
            Logger.info("A股市场模拟系统已停止");
        }
    }

    private void updateAllStockPrices() {
        if (!isMarketOpen()) {
            Logger.info("周末休市，暂停更新股票价格");
            return;
        }
        List<String> symbols = new ArrayList<>(plugin.getConfig().getStringList("stocks"));

        symbols.forEach(symbol -> {
            fetchStockPrice(symbol);
            try { Thread.sleep(REQUEST_INTERVAL); }
            catch (InterruptedException e) { Thread.currentThread().interrupt(); }
        });
    }

    private void fetchStockPrice(String symbol) {
        try {
            double newPrice = getRealStockPrice(symbol);
            newPrice = applyMarketFluctuation(newPrice);
            updateStockPrice(symbol, newPrice);
        } catch (Exception e) {
            failureCounts.putIfAbsent(symbol, 0);
            int failures = failureCounts.get(symbol) + 1;
            failureCounts.put(symbol, failures);
            Logger.error("股票[" + symbol + "]数据获取失败: " + e.getMessage());
            double current = cacheManager.getCachedPrice(symbol);
            double fluctuation = 0.98 + (0.04 * Math.random());
            updateStockPrice(symbol, current * fluctuation);
            if (failures >= 3) {
                removeFailedStock(symbol);
                failureCounts.remove(symbol);
            }
        }
    }

    private void updateStockPrice(String symbol, double newPrice) {
        double oldPrice = cacheManager.getCachedPrice(symbol);
        cacheManager.cachePreviousPrice(symbol, oldPrice);
        cacheManager.cacheStockPrice(symbol, newPrice);
        dispatchPriceUpdate(symbol, oldPrice, newPrice);
    }

    public ApiProvider getCurrentApiProvider() { return currentApiProvider; }
    public String getStockName(String symbol) {
        String lowerSymbol = symbol.toLowerCase();
        int retryCount = 0;

        while (retryCount < 2) {
            if (!cacheManager.isStockLoaded(lowerSymbol)) {
                loadStockIfNeeded(lowerSymbol);
            }

            String name = cacheManager.getStockName(lowerSymbol);

            if (name != null && !name.trim().isEmpty() &&
                    !name.equalsIgnoreCase(lowerSymbol) &&
                    !name.contains("未知股票") &&
                    !name.contains("加载失败") &&
                    !name.matches("^[0-9]+$")) {
                return name;
            }

            try {
                name = getStockNameFromAPI(lowerSymbol);
                cacheManager.cacheStockName(lowerSymbol, name);
                cacheManager.markStockLoaded(lowerSymbol);
                retryCount++;
            } catch (Exception e) {
                break;
            }
        }

        return "股票:" + symbol;
    }

    public Double getStockPrice(String symbol) {
        String lowerSymbol = symbol.toLowerCase();
        if (!cacheManager.isStockLoaded(lowerSymbol)) loadStockIfNeeded(lowerSymbol);
        return cacheManager.getCachedPrice(lowerSymbol);
    }

    public Map<String, Double> getStockPrices() { return cacheManager.getAllStockPrices(); }

    public double getChangePercent(String symbol) {
        Double current = cacheManager.getCachedPrice(symbol);
        Double previous = cacheManager.getPreviousPrice(symbol);
        if (current == null || previous == null) return 0.0;
        double changePercent = ((current - previous) / previous) * 100;
        return Math.round(changePercent * 100.0) / 100.0;
    }

    private double applyMarketFluctuation(double price) {
        double fluctuation = 0.96 + (0.08 * Math.random());
        double newPrice = price * fluctuation;

        newPrice = Math.max(0.1, Math.min(newPrice, 10000.0));

        return Math.round(newPrice * 100.0) / 100.0;
    }

    private void dispatchPriceUpdate(String symbol, double oldPrice, double newPrice) {
        plugin.getServer().getPluginManager().callEvent(
                new StockPriceUpdateEvent(symbol, oldPrice, newPrice)
        );
    }

    public void addStockToMonitoring(String symbol) {
        String lowerSymbol = symbol.toLowerCase();

        if (!isStockLoaded(lowerSymbol)) return;

        List<String> stocks = plugin.getConfig().getStringList("stocks");
        if (!stocks.contains(lowerSymbol)) {
            stocks.add(lowerSymbol);
            plugin.getConfig().set("stocks", stocks);
            plugin.saveConfig();
        }
    }

    public boolean addStockToConfig(String symbol) {
        if (getStockPrice(symbol) != null) {
            return true;
        }

        if (!loadStockIfNeeded(symbol)) {
            return false;
        }

        List<String> stocks = plugin.getConfig().getStringList("stocks");
        if (!stocks.contains(symbol.toLowerCase())) {
            stocks.add(symbol.toLowerCase());
            plugin.getConfig().set("stocks", stocks);
            plugin.saveConfig();
            Logger.info("已将新股票 " + symbol + " 添加到配置文件");
        }

        addStockToMonitoring(symbol);
        return true;
    }

    private void removeFailedStock(String symbol) {
        // 从缓存中移除
        cacheManager.stockPrices.remove(symbol);
        cacheManager.previousPrices.remove(symbol);
        cacheManager.stockNames.remove(symbol);
        cacheManager.lastApiCall.remove(symbol);
        cacheManager.loadedStocks.remove(symbol);

        // 从配置文件中移除
        List<String> stocks = plugin.getConfig().getStringList("stocks");
        if (stocks.remove(symbol)) {
            plugin.getConfig().set("stocks", stocks);
            plugin.saveConfig();
            Logger.warn("已移除无法更新的股票: " + symbol);
        }
    }

    public boolean isStockLoaded(String symbol) {
        return cacheManager.isStockLoaded(symbol.toLowerCase());
    }

    public boolean isMarketOpen() {
        Calendar calendar = Calendar.getInstance();
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        return dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY;
    }
}
